package main

import "fmt"

type Pet interface {
	SetName(name string)
	Name() string
	Category() string
}

//对于任何数据类型，只要它的方法集合中完全包含了一个接口的全部特征（即全部的方法），
//那么它就一定是这个接口的实现类型
//我声明了一个接口类型Pet，它包含了 3 个方法定义，方法名称分别为SetName、Name和Category。
//这 3 个方法共同组成了接口类型Pet的方法集合。
//只要一个数据类型的方法集合中有这 3 个方法，那么它就一定是Pet接口的实现类型。这是一种无侵入式的接口实现方式。
type Dog struct {
	name string
}

func (dog *Dog) SetName(name string) {
	dog.name = name
}

func (dog Dog) Name() string {
	return dog.name
}

func (dog Dog) Category() string {
	return "dog"
}

func main() {

	//Dog类型本身的方法集合中只包含了 2 个方法，也就是所有的值方法。
	//他没有实现所有的3个方法

	//而它的指针类型*Dog方法集合却包含了 3 个方法，
	//也就是说，它拥有Dog类型附带的所有值方法和指针方法。
	//又由于这3个方法恰恰分别是Pet接口中某个方法的实现，
	//所以*Dog类型就成为了Pet接口的实现类型。

	dog := Dog{"little pig"}
	_, ok := interface{}(dog).(Pet)                      //类型断言，判断dog是否是Pet类型
	fmt.Printf("Dog implements interface Pet: %v\n", ok) //false

	_, ok = interface{}(&dog).(Pet)
	fmt.Printf("*Dog implements interface Pet: %v\n", ok) //true

	dog.SetName("pig")
	fmt.Println(dog.Name())
	fmt.Println(dog.Category())

	var pet Pet = &dog
	fmt.Printf("This pet is a %s, the name is %q.\n", pet.Category(), pet.Name())
}
